#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <unistd.h>  
#include <event2/event.h>  
#include <event2/event_struct.h>  
#include "WorkerWithQueue.h"
  
#define SERVER_IP "127.0.0.1"  
#define SERVER_PORT 7100
#define BUFFER_SIZE 1024  
static int clientFd = -1;
static bool isSwitch = false;
static int cnt = 0;
static SafeDeque<int> deque;
struct event *ev_time;
struct event *clientEv;
bool hasAddEvent = false;

void timeout_callback(evutil_socket_t fd, short events, void *arg) {
    cnt++;
    printf("timeout_callback cnt: %d\n", cnt);
    deque.push(cnt);
    if (cnt < 20 && !hasAddEvent) {
        event_add(clientEv, NULL);
        hasAddEvent = true;
    }
}


// 读取数据时的回调函数  
void event_callback(evutil_socket_t fd, short events, void *arg) {
    // printf("read_callback...\n");
    struct sockaddr_in server_addr;
    ssize_t nread;
    if (events & EV_READ) {
        // printf("read_callback... EV_READ\n");
        char buffer[BUFFER_SIZE];  
  
        // 从UDP套接字读取数据
        socklen_t server_len = sizeof(server_addr);
        nread = recvfrom(fd, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&server_addr, &server_len);  
        if (nread > 0) {  
            buffer[nread] = '\0'; // Null-terminate the string  
            // printf("Received %zd bytes from %s:%d: %s\n", nread, inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port), buffer);

            struct timeval currentTv;
            event_base_gettimeofday_cached((struct event_base *)arg, &currentTv);
            printf("Current time: %ld.%ld\n", currentTv.tv_sec, currentTv.tv_usec);

            if (strncmp(buffer, "quit", 4) == 0) {
                printf("quit client\n");
                if (ev_time) {
                    event_del(ev_time);
                    event_free(ev_time);
                }
                event_base_loopexit((struct event_base *)arg, NULL);
            } else if (strncmp(buffer, "nps", 3) == 0) {
                printf("start time\n");
                struct timeval tv;
                evutil_timerclear(&tv);
                tv.tv_sec = 3;          
                ev_time = event_new((struct event_base *)arg, -1, EV_TIMEOUT | EV_PERSIST, timeout_callback, (void*)&ev_time);
                // 执行一次
                // ev_time = event_new((struct event_base *)arg, -1, EV_TIMEOUT, timeout_callback, (void*)&ev_time);
                evtimer_add(ev_time, &tv);

                // 执行一次的便捷接口
                // event_base_once((struct event_base *)arg, -1, EV_TIMEOUT, timeout_callback, (void*)&ev_time, &tv);

            }
        } else {  
            perror("Error reading from UDP socket");  
        }  
    }  
    // 如果需要，可以在这里处理可写事件  
    if (events & EV_WRITE) {  
        int tmpCnt = 0;
        printf("EV_WRITE.....\n");
        if (deque.wait_for_and_pop(tmpCnt)) {
            // 处理可写逻辑，例如发送数据  
            std::string buffer = "hello libevent udp, cnd: " + std::to_string(tmpCnt) + "\n";
            memset(&server_addr, 0, sizeof(server_addr));
            server_addr.sin_family = AF_INET;
            server_addr.sin_port = htons(7077);
            inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);
            isSwitch = !isSwitch;
            ssize_t nsend = sendto(fd, buffer.c_str(), buffer.length(), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
            // ssize_t nsend = sendto(fd, buffer, strlen(buffer), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
            printf("Sent %zd bytes from %s:%d: %s\n", nsend, SERVER_IP, 7077, buffer.c_str());
        } else if (hasAddEvent) {
            hasAddEvent = false;
            event_del(clientEv);
        }


    }  
}  
  
// 事件错误处理回调  
void event_error_callback(evutil_socket_t fd, short events, void *arg) {  
    perror("Error from event");  
    // 关闭套接字或退出程序  
}  
  
int main(int argc, char **argv) {  
    struct event_base *base;  
    struct event *ev;  
    int sockfd;  
    struct sockaddr_in server_addr;  
    evutil_socket_t fd;  
  
    // 创建UDP套接字  
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);  
    if (sockfd < 0) {  
        perror("socket creation failed");  
        exit(EXIT_FAILURE);  
    }

    // clientFd = socket(AF_INET, SOCK_DGRAM, 0);

    // 设置服务器地址  
    memset(&server_addr, 0, sizeof(server_addr));  
    server_addr.sin_family = AF_INET;  
    server_addr.sin_port = htons(SERVER_PORT);  
    inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);  
    evutil_make_listen_socket_reuseable(sockfd);

    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {  
        perror("bind failed");  
        exit(EXIT_FAILURE);  
    }
    evutil_make_socket_nonblocking(sockfd);
  
    // 初始化Libevent事件循环  
    base = event_base_new();  
    if (!base) {  
        fprintf(stderr, "Could not initialize libevent!\n");  
        exit(EXIT_FAILURE);  
    }  
  
    // 创建事件以检测可读和可写  
    // ev = event_new(base, sockfd, EV_READ | EV_WRITE | EV_PERSIST , event_callback, base);  
    ev = event_new(base, sockfd, EV_READ | EV_PERSIST , event_callback, base);  
    if (!ev) {  
        fprintf(stderr, "Could not create event!\n");  
        exit(EXIT_FAILURE);  
    }  
    // clientEv = event_new(base, clientFd, EV_WRITE | EV_PERSIST , event_callback, base);  
    clientEv = event_new(base, sockfd, EV_WRITE | EV_PERSIST , event_callback, base);  
    if (!clientEv) {
        fprintf(stderr, "Could not create clientEv event!\n");  
        exit(EXIT_FAILURE);  
    }
  
    // 设置错误处理回调  
    // event_set_error_cb(ev, event_error_callback);  
  
    // 将事件添加到事件循环中  
    event_add(ev, NULL);  

    // struct event ev_time;
    // event_assign(&ev_time, base, -1, EV_PERSIST, timeout_callback, (void*)&ev_time);
    // struct timeval tv;
    // evutil_timerclear(&tv);
    // tv.tv_sec = 3;          
    // event_add(&ev_time, &tv);
  
    // 发送一些初始数据（可选）  
    // char *message = "Hello, UDP server!";  
    // sendto(sockfd, message, strlen(message), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));  
  
    // 启动事件循环  
    event_base_dispatch(base);  
  
    // 清理资源  
    event_free(ev);  
    event_free(clientEv);  
    event_base_free(base);  
    close(sockfd);  
  
    return 0;  
}